package com.bims.jreport.dao;


import com.bims.jreport.entity.TPageEntity;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.jooq.*;
import org.jooq.impl.TableImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
@Component
public class JooqDaoUtil {

    public static final int[] EMPTY_INT = {};
    public static final Record[] EMPTY_RECORD = {};
    public static final Collection<Condition> EMPTY_CONDITION_COLLECTION = Collections.unmodifiableCollection(new ArrayList<Condition>(0));
    public static final Collection<? extends SortField<?>> EMPTY_SORT_COLLECTION = Collections.unmodifiableCollection(new ArrayList<>(0));


    @Autowired
    private DSLContext dsl;
    private Map<Class<?>, JooqDao> daoCache = new ConcurrentHashMap<>();

    public <T extends TableImpl<R>, R extends UpdatableRecord<R>> JooqDao<T, R> getDao(T table) {
        Class<?> tClass = table.getClass();
        if (daoCache.containsKey(tClass)) {
            return daoCache.get(tClass);
        }
        val dao = new JooqDao<>(table);
        dao.setDsl(dsl);
        daoCache.put(tClass, dao);
        return dao;
    }


    /**
     * 获取DSLContext对象
     *
     * @return
     */
    public DSLContext getDsl() {
        return dsl;
    }


    /**
     * 获取表的主键数组
     *
     * @param table
     * @return
     */
    public Field<?>[] getTablePKs(TableImpl table) {
        return JooqDao.getTablePKs(table);
    }

    /**
     * 如果字段不可为空，但字段当前值为空，设置该字段未改变
     *
     * @param record
     */
    public void resetNotNullFieldChangeState(Record record) {
        JooqDao.resetNotNullFieldChangeState(record);
    }

    /**
     * 根据表 和 pojo对象，获取新的record记录
     * 对于一些字段，如果不可为空，但是当前数据为空，则设置为不更新状态
     *
     * @param table
     * @param obj
     * @param updatePks 新纪录是否要更新主键字段
     * @return
     */
    public <T extends TableImpl<R>, R extends UpdatableRecord<R>> R getNewRecord(T table, Object obj, boolean updatePks) {
        val rcd = getNewRecord(table, obj);
        if (!updatePks) {
            Field<?>[] pks = getTablePKs(table);
            for (Field<?> field : pks) {
                rcd.changed(field, false);
            }
        }
        return rcd;
    }

    /**
     * 根据表 和 pojo对象，获取新的record记录
     * 对于一些字段，如果不可为空，但是当前数据为空，则设置为不更新状态
     *
     * @param table
     * @param obj
     * @return
     */
    public <T extends TableImpl<R>, R extends UpdatableRecord<R>> R getNewRecord(T table, Object obj) {
        if (obj == null) {
            return dsl.newRecord(table);
        }
        val record = dsl.newRecord(table, obj);
        resetNotNullFieldChangeState(record);
        return record;
    }

    /**
     * 获取一个空的record
     *
     * @param table
     * @param <T>
     * @param <R>
     * @return
     */
    public <T extends TableImpl<R>, R extends UpdatableRecord<R>> R getNewRecord(T table) {
        return dsl.newRecord(table);
    }


    /**
     * @param page             分页信息
     * @param tbls             关联表或单独表
     * @param conditions       条件
     * @param orderCollections
     */
    public void pageQuery(TPageEntity<Record> page, Table tbls, Collection<Condition> conditions, Collection<? extends SortField<?>> orderCollections) {
        if (conditions == null) {
            conditions = EMPTY_CONDITION_COLLECTION;
        }
        if (orderCollections == null) {
            orderCollections = EMPTY_SORT_COLLECTION;
        }
        int count = dsl.selectCount().from(tbls).where(conditions).fetchOne(0, Integer.class);
        page.setEntityCount(count);
        int start = (page.getPageNo() - 1) * page.getPageSize();
        if (start < count) {


            val list = dsl.select(tbls.fields()).from(tbls).where(conditions).orderBy(orderCollections).limit(start, page.getPageSize()).fetch();
            page.setEntities(list);
        }
    }

    /**
     * 根据联合表或者表，查询条件，查询是否存在相应记录
     *
     * @param tbls
     * @param condition
     * @return
     */
    public boolean fetchExists(Table tbls, Condition condition) {
        if (condition == null) {
            return dsl.fetchExists(tbls);
        }
        return dsl.fetchExists(tbls, condition);
    }

    /**
     * 根据查询语句查询是否有存在相应记录
     *
     * @param query
     * @return
     */
    public boolean fetchExist(Select<?> query) {
        return dsl.fetchExists(query);
    }



}
